#pragma once
#include <iostream>
#include <windows.h>
#include <TlHelp32.h>
#include <comdef.h>
#include <vector>
#include <cstdint>
#include <sstream>
using namespace std;
// 郝新龙的内存操作类
class HxlM {
public:
  typedef struct {
    HWND hwndWindow;   // 窗口句柄
    DWORD dwProcessID; // 进程ID
  }EnumWindowsArg;
public:
  HxlM();
  ~HxlM();
public://内存相关操作
  // 根据进程id获取句柄
  static HWND getHandleByPID(const DWORD dwProcessID) {
    HWND hwndRet = nullptr;
    EnumWindowsArg ewa;
    ewa.dwProcessID = dwProcessID;
    ewa.hwndWindow = nullptr;
    EnumWindows(EnumWindowsProc,(LPARAM)&ewa);
    if (ewa.hwndWindow) {
      hwndRet = ewa.hwndWindow;
    }
    return hwndRet;
  }
  // 根据名字获取进程id
  static DWORD getPIidByName(const char* name) {
    const HANDLE hsnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0);
    if (hsnapshot == INVALID_HANDLE_VALUE) {
      cout << "Create TlHelp32 Error!" << endl;
      return -1;
    }
    PROCESSENTRY32 processer;
    processer.dwSize = sizeof(PROCESSENTRY32);

    int flag = Process32First(hsnapshot,&processer);
    while (flag != 0) {
      _bstr_t processName(processer.szExeFile);  //WCHAR字符串转换成CHAR字符串
      if (strcmp(processName,name) == 0) {
        return processer.th32ProcessID;        //返回进程ID
      }
      flag = Process32Next(hsnapshot,&processer);
    }

    CloseHandle(hsnapshot);
    return -2;
  }
  // 根据窗口类名和标题获取窗口句柄
  static HWND findWindow(const LPCWSTR lpClassName,const LPCWSTR lpWindowName) {
    return FindWindow(lpClassName,lpWindowName);
  }
  // 获取指定进程数据
  template<class T>
  static int getData(const long processId,const long addr,T& data) {
    const HANDLE processHandle = OpenProcess(PROCESS_VM_READ,FALSE,processId);
    if (processHandle == nullptr) {
      return -1;
    }
    SIZE_T bytesRead = 0;
    const int status = ReadProcessMemory(processHandle,(void*)addr,&data,sizeof(data),&bytesRead);
    if (!status) {
      CloseHandle(processHandle);
      return -1;
    }
    CloseHandle(processHandle);
    return 0;
  }
  // 设置指定进程内存数据
  template<class T>
  static int setData(const long processId,const long addr,T data) {
    const HANDLE processHandle = OpenProcess(PROCESS_ALL_ACCESS,FALSE,processId);
    if (processHandle == nullptr) {
      return -1;
    }
    const int status = WriteProcessMemory(processHandle,(void*)addr,&data,sizeof(8),nullptr);
    if (!status) {
      CloseHandle(processHandle);
      return -1;
    }
    CloseHandle(processHandle);
    return 0;
  }
  // 获取窗口矩形
  static int getWindowRect(const HWND handle,RECT& rect) {
    const int status = GetWindowRect(handle,&rect);
    if (!status) {
      return 0;
    }
    return 1;
  }
  // 获取矩阵数据
  static int getMatrixFromMem(const long processId,const long addr,vector<vector<float>>& matrix) {
    const HANDLE processHandle = OpenProcess(PROCESS_VM_READ,FALSE,processId);
    if (processHandle == nullptr) {
      return -1;
    }
    long realAddr = addr;
    const int size = 4 * 4 * sizeof(int);
    for (int i = 0; i < 4; i++) {
      for (int j = 0; j < 4; j++) {
        float value = 0;
        const int status = ReadProcessMemory(processHandle,(void*)realAddr,&value,sizeof(int),nullptr);
        if (!status) {
          return -1;
        }
        realAddr += 4;
        matrix[i].push_back(value);
      }
    }
    CloseHandle(processHandle);
    return 0;
  }
  // 根据句柄获取进程id
  static long getPidByHandle(const long handle) {
    long processId = 0;
    GetWindowThreadProcessId((HWND)handle,(LPDWORD)&processId);
    return processId;
  }
  // 用于把long类型转为16进制字符串
  template<class T>
  static string transIntToHex(const T value) {
    ostringstream oss;
    oss << hex << value;
    return oss.str();
  }
  // 用于unicode转为多字符
  static string unToAnsi(const char* str) {
    const int length = WideCharToMultiByte(0,0,(LPCWCH)str,-1,nullptr,0,nullptr,nullptr);
    char szChar[200] = "";
    WideCharToMultiByte(0,0,(LPCWCH)str,-1,szChar,length * 2,nullptr,nullptr);
    return string(szChar);
    //int length ＝ WideCharToMultiByte(0,0,str.,-1,0,0,0,0)
  }
  // 将big5转为gbk
  static string big5ToGbk(char* str) {
    char str1[100] = {0};
    strcpy_s(str1,str);
    if (!strcmp(str1,"")) return str1;
    int nStrLen = strlen(str1);
    wchar_t* pws = new wchar_t[nStrLen + 1];
    try {   //CP_UTF8
      int nReturn = MultiByteToWideChar(950,0,str1,nStrLen,pws,nStrLen + 1);
      BOOL bValue = false;
      nReturn = WideCharToMultiByte(936,0,pws,nReturn,str1,nStrLen + 1,"?",&bValue);
      str1[nReturn] = 0;
    } catch (exception& e) {
      delete[] pws;
    }
    return str1;
  }
  // 用于申请内存空间
  static void* allocMem(const long processId,const int size = 1024) {
    const HANDLE processHandle = OpenProcess(PROCESS_ALL_ACCESS,FALSE,processId);
    if (processHandle == nullptr) {
      return nullptr;
    }
    void* ptr = VirtualAllocEx(processHandle,nullptr,size,4096,64);
    CloseHandle(processHandle);
    return ptr;
  }
  // 用于释放空间
  static void freeMen(const long processId,void* ptr,const int size = 1024) {
    if (size == 0 || ptr == nullptr) {
      return;
    }
    const HANDLE processHandle = OpenProcess(PROCESS_ALL_ACCESS,FALSE,processId);
    if (processHandle == nullptr) {
      return;
    }
    VirtualFreeEx(processHandle,ptr,size,MEM_RELEASE);
  }
  // 根据字符串获取指定的数据-注入
  template<class T>
  static void getDataByString(string str,T& data) {
    const vector<string> arr = split(str,']');
    long before = 0,i = 0;
    const string last = arr[arr.size() - 1];
    bool endIsAdd = last.empty();
    const int lastIndex = endIsAdd ? arr.size() - 2 : arr.size() - 1;
    for (auto& basicString : arr) {
      if (i == lastIndex) {
        std::cout << stol(basicString,0,16);
        data = *(long*)(before + stol(basicString,0,16));
        break;
      } else {
        before = *(long*)(before + stol(basicString,0,16));
        i++;
      }
      if (before == 0) {
        throw exception("error point");
      }
    }
  }
  // 用于根据字符串获取指定的数据
  template<class T>
  static void getDataByString(string str,T& data,const long processId) {
    const vector<string> arr = split(str,']');
    long before = 0,i = 0;
    const string last = arr[arr.size() - 1];
    bool endIsAdd = last.empty();
    for (auto& basicString : arr) {
      const int lastIndex = endIsAdd ? arr.size() - 2 : arr.size() - 1;
      if (i == lastIndex) {
        getData(processId,before + stol(basicString,nullptr,16),data);
        break;
      } else {
        getData(processId,before + stol(basicString,nullptr,16),before);
        i++;
      }

    }
  }
public: // 字符串相关
  // 用于切割字符串
  static vector<string> split(string& str,const char ch) {
    vector<string> strArr;
    int pos = 0;
    while (true) {
      const int newPos = str.find(ch,pos);
      if (newPos == string::npos) {
        strArr.push_back(str.substr(pos));
        break;
      }
      strArr.push_back(str.substr(pos,newPos - pos));
      pos = newPos + 1;
    }
    return strArr;
  }
public:// 调试输出相关
  static void dbgLog(const char* pszFormat,...) {
#ifdef _DEBUG
    char szbufFormat[0x1000];
    char szbufFormat_Game[0x1100] = "";
    va_list argList;
        va_start(argList,pszFormat);//参数列表初始化
    vsprintf_s(szbufFormat,pszFormat,argList);
    strcat_s(szbufFormat_Game,szbufFormat);
    OutputDebugStringA(szbufFormat_Game);
        va_end(argList);
#endif
  }
private:
  // 枚举窗口回调函数
  static BOOL CALLBACK EnumWindowsProc(const HWND hwnd,const LPARAM lParam) {
    EnumWindowsArg* pArg = (EnumWindowsArg*)lParam;
    DWORD dwProcessID = 0;
    GetWindowThreadProcessId(hwnd,&dwProcessID); // 通过窗口句柄取得进程ID
    if (dwProcessID == pArg->dwProcessID) {
      pArg->hwndWindow = hwnd;
      return FALSE;    // 返回FALSE：找到了
    }
    return TRUE;// 返回TRUE：没找到，继续找，
  }
  static int strHexToHex(const string str);
  static uint8_t floatToByte(float value);
};

